package org.victoriest.server.handler;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.springframework.stereotype.Service;
import org.victoriest.server.dto.MessageModel;
import org.victoriest.server.dto.RoomModel;
import org.victoriest.server.event.VictoriestEvent;
import org.victoriest.server.protocol.Protocol;
import org.victoriest.server.service.HandlerService;
import org.victoriest.server.util.MessageSender;

@Service("endrawingHandlerServ")
public class EndrawingHandler extends SimpleChannelHandler {

	protected Logger LOGGER = Logger.getLogger(getClass());

	@Resource(name = "systemHandlerServ")
	private HandlerService systemHandlerServ;

	public static final ChannelGroup ALL_CHANNELS = new DefaultChannelGroup(
			"DEFAULT-CHANNELS");
	
	@Resource(name = "groupsMap")
	private Map<String, ChannelGroup> groupsMap;
	
	@Resource(name = "channelIdMappingRoomModel")
	private Map<Integer, RoomModel> channelIdMappingRoomModel;
	
	@Resource(name = "groupNameMappingChannelId")
	private Map<String, Integer> groupNameMappingChannelId;

	@Override
	public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		LOGGER.info("A channel has connected! id:" + e.getChannel().getId());
	}

	@Override
	public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e)
			throws Exception {
		LOGGER.info("A channel has closed! id:" + e.getChannel().getId());
		actionOnDisconnected(ctx.getChannel());
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
			throws Exception {
		VictoriestEvent event = (VictoriestEvent) e.getMessage();
		switch (event.getType()) {
		case TYPE_HEART_BEAT:
			break;
		case TYPE_LOGIN_REQ:
			systemHandlerServ.process(e.getChannel(), event);
			break;
		case TYPE_ENTER_HALL_REQ:
			enterHall(e.getChannel(), event);
			break;
		case TYPE_CREATE_ROOM_REQ:
			createRoom(e.getChannel(), event);
			break;
		case TYPE_ENTER_ROOM_REQ:
			enterRoom(e.getChannel(), event);
			break;
		case TYPE_FEACH_ROOM_REQ:
			feachRoom(e.getChannel(), event);
			break;
		case TYPE_CHAT_REQ:
			chat(e.getChannel(), event);
			break;
		case TYPE_QUIT_ROOM_REQ:
			quitRoom(e.getChannel(), event);
			break;
		case TYPE_QUIT_HALL_REQ:
			actionOnDisconnected(e.getChannel());
			break;
		default:
			actionOnDisconnected(e.getChannel());
		}
	}

	// 进入大厅
	@SuppressWarnings("rawtypes")
	private void enterHall(Channel channel, VictoriestEvent event) {
		if(ALL_CHANNELS.contains(channel)){
			// 此人已经入大厅
			MessageSender.write(channel, Protocol.TYPE_ENTER_HALL_RES, 1);
		}
		else{
			// 加入大厅频道
			ALL_CHANNELS.add(channel);
			MessageSender.write(channel, Protocol.TYPE_ENTER_HALL_RES, 0);
		}
	}

	// 创建房间
	private void createRoom(Channel channel, VictoriestEvent<RoomModel> event) {
		RoomModel model = event.getSource();
		String groupName = model.getName();
		if(groupsMap.containsKey(groupName)){
			// 此房间名被占用
			MessageSender.write(channel, Protocol.TYPE_CREATE_ROOM_RES, 1);
			return;
		}
		if(channelIdMappingRoomModel.containsKey(channel.getId())){
			// 此用户已经建立了个房间
			MessageSender.write(channel, Protocol.TYPE_CREATE_ROOM_RES, 2);
			return;
		}
		// 开始创建房间
		ChannelGroup group = new DefaultChannelGroup(groupName);
		group.add(channel);
		// 设置房间玩家列表
		List<Integer> roomUsers = new ArrayList<Integer>();
		roomUsers.add(channel.getId());
		model.setUsers(roomUsers);
		channelIdMappingRoomModel.put(channel.getId(), model);
		groupsMap.put(groupName, group);
		groupNameMappingChannelId.put(groupName, channel.getId());
		// 房间创建成功
		MessageSender.write(channel, Protocol.TYPE_CREATE_ROOM_RES, 0);
		roomUsers = null;
	}

	private void enterRoom(Channel channel, VictoriestEvent<String> event) {
		String groupName = event.getSource();
		if(!groupsMap.containsKey(groupName)){
			// 没有此房间
			MessageSender.write(channel, Protocol.TYPE_ENTER_ROOM_RES, 1);
		}
		ChannelGroup group = groupsMap.get(groupName);
		if(group.contains(channel)){
			// 用户已在房间里
			MessageSender.write(channel, Protocol.TYPE_ENTER_ROOM_RES, 2);
		}
		int ownerId = groupNameMappingChannelId.get(groupName);
		RoomModel room = channelIdMappingRoomModel.get(ownerId);
		if(room.getRoomLimit() <= room.getUsers().size()){
			// 房间满了
			MessageSender.write(channel, Protocol.TYPE_ENTER_ROOM_RES, 3);
			return;
		}
		group.add(channel);
		room.getUsers().add(channel.getId());
		MessageSender.write(channel, Protocol.TYPE_ENTER_ROOM_RES, 0);
	}

	private void quitRoom(Channel channel, VictoriestEvent<String> event) {
		String groupName = event.getSource();
		if(!groupsMap.containsKey(groupName)){
			// 没有这个房间
			MessageSender.write(channel, Protocol.TYPE_QUIT_ROOM_RES, 1);
			return;
		}
		int ownerId = groupNameMappingChannelId.get(groupName);
		RoomModel room = channelIdMappingRoomModel.get(ownerId);
		if(!room.getUsers().contains(channel.getId())){
			// 这货不在这房间里
			MessageSender.write(channel, Protocol.TYPE_QUIT_ROOM_RES, 2);
			return;
		}
		// 开始退房间了
		room.getUsers().remove(channel.getId());
		ChannelGroup group = groupsMap.get(groupName);
		group.remove(channel);
		MessageSender.write(channel, Protocol.TYPE_QUIT_ROOM_RES, 0);
	}


	@SuppressWarnings("rawtypes")
	private void feachRoom(Channel channel, VictoriestEvent event) {
		String[] result = new String[groupsMap.size()];
		groupsMap.keySet().toArray(result);
		MessageSender.write(channel, Protocol.TYPE_FEACH_ROOM_RES, result);
		result = null;
	}

	private void chat(Channel channel, VictoriestEvent<MessageModel> event) {
		if (!ALL_CHANNELS.contains(channel))
			return;
		if (!(event.getSource() instanceof MessageModel)) {
			MessageSender.write(channel, Protocol.TYPE_CHAT_RES, null);
			return;
		}
		MessageModel message = (MessageModel) event.getSource();
		switch(message.getType()){
		case 1:
			MessageSender.write(ALL_CHANNELS, Protocol.TYPE_CHAT_RES, message);
			return;
		case 2:
			String groupName = String.format("group_%s", message.getReceiverChannelOrGroupId());
			if(!groupsMap.containsKey(groupName)){
				MessageSender.write(channel, Protocol.TYPE_CHAT_RES, null);
				return;
			}
			ChannelGroup group = groupsMap.get(groupName);
			MessageSender.write(group, Protocol.TYPE_CHAT_RES, message);
			return;
		case 3:
			Channel c = ALL_CHANNELS.find(message.getReceiverChannelOrGroupId());
			if(c == null){
				MessageSender.write(channel, Protocol.TYPE_CHAT_RES, null);
			}
			MessageSender.write(c, Protocol.TYPE_CHAT_RES, message);
			return;
		default:
			return;
		}
	}

	private void actionOnDisconnected(Channel channel) {
		ALL_CHANNELS.remove(channel);
		channel.close();
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
			throws Exception {
		LOGGER.warn("A exception caught! id:", e.getCause());
		actionOnDisconnected(e.getChannel());
	}

}
